home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint96sb.zoo / src / tty.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-18  |  18.2 KB  |  797 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /*
  6.  * read/write routines for TTY devices
  7.  */
  8.  
  9. #include "mint.h"
  10.  
  11. static void _erase P_((FILEPTR *, int));
  12. static int escseq P_((struct tty *, int));
  13.  
  14. /* setting a special character to this value disables it */
  15. #define UNDEF 0
  16.  
  17.  
  18. /* default terminal characteristics */
  19.  
  20. struct tty default_tty = {
  21.     0,            /* process group */
  22.     0,            /* state */
  23.     0,            /* use_cnt */
  24.     0,            /* reserved short */
  25.     {
  26.     13, 13,            /* input speed == output speed == 9600 baud */
  27.     CTRL('H'),        /* erase */
  28.     CTRL('U'),        /* kill */
  29.     T_ECHO|T_CRMOD|T_TOSTOP|T_XKEY, /* flags */
  30.     },
  31.     {
  32.     CTRL('C'),        /* interrupt */
  33.     CTRL('\\'),        /* quit */
  34.     CTRL('Q'),        /* start */
  35.     CTRL('S'),        /* stop */
  36.     CTRL('D'),        /* EOF */
  37.     '\r'            /* alternate end of line */
  38.     },
  39.     {
  40.     CTRL('Z'),        /* suspend */
  41.     CTRL('Y'),        /* suspend after read */
  42.     CTRL('R'),        /* reprint */
  43.     UNDEF,            /* flush output */
  44.     CTRL('W'),        /* erase word */
  45.     CTRL('V')        /* quote next char */
  46.     },
  47.     {
  48.     0, 0, 0, 0        /* window size is unknown */
  49.     },
  50.     0,            /* no process is selecting us for reading */
  51.     0,            /* or for writing */
  52.     0            /* use default XKEY map */
  53. };
  54.  
  55. #define _put(f, c) (tty_putchar((f), (c), RAW))
  56.  
  57. static void
  58. _erase(f, c)
  59.     FILEPTR *f;
  60.     int c;
  61. {
  62.     _put(f, '\010');
  63.     _put(f, ' ');
  64.     _put(f, '\010');
  65. /* watch out for control characters -- they're printed as e.g. "^C" */
  66. /* BUG: \t is messed up. We really need to keep track of the output
  67.  * column
  68.  */
  69.     if (c >= 0 && c < ' ' && c != '\t') {
  70.         _put(f, '\010'); _put(f, ' '); _put(f, '\010');
  71.     }
  72. }
  73.  
  74. #define put(f, c)   { if (mode & T_ECHO) _put(f, c); }
  75. #define erase(f, c) { if (mode & T_ECHO) _erase(f, c); }
  76.  
  77. long
  78. tty_read(f, buf, nbytes)
  79.     FILEPTR *f;
  80.     void *buf;
  81.     long nbytes;
  82. {
  83.     long r;
  84.     long bytes_read = 0;
  85.     unsigned char ch, *ptr;
  86.     int rdmode, mode;
  87.     struct tty *tty;
  88.  
  89.     tty = (struct tty *)f->devinfo;
  90.     assert(tty != 0);
  91.  
  92.     if (f->flags & O_HEAD) {    /* pty server side? */
  93.         rdmode = RAW;        /* yes -- always raw mode */
  94.         mode = T_RAW;
  95.     }
  96.     else if (curproc->domain == DOM_MINT) {    /* MiNT domain process? */
  97.         mode = tty->sg.sg_flags;
  98.         rdmode = COOKED|NOECHO;
  99.         if ( mode & (T_RAW | T_CBREAK) ) {
  100.             rdmode = (mode & T_RAW) ? RAW : COOKED;
  101.         }
  102.         if (mode & T_XKEY)
  103.             rdmode |= ESCSEQ;
  104.     }
  105.     else {
  106.         rdmode = COOKED|NOECHO;
  107.         mode = T_TOS | T_ECHO;
  108.     }
  109.  
  110.     ptr = buf;
  111.  
  112.     while (bytes_read < nbytes) {
  113.         r = tty_getchar(f, rdmode);
  114.         if (r < 0) {
  115. tty_error:
  116.             DEBUG(("tty_read: tty_getchar returned %ld", r));
  117.             return (bytes_read) ? bytes_read : r;
  118.         }
  119.         else if (r == MiNTEOF)
  120.             return bytes_read;
  121.         ch = r & 0xff;
  122.  
  123.         if ( (mode & T_CRMOD) && (ch == '\r') )
  124.             ch = '\n';
  125.  
  126. /* 1 character reads in TOS mode are always raw */
  127.         if (nbytes == 1 && (mode & T_TOS)) {
  128.             put(f, ch);
  129.             *ptr = ch;
  130.             return 1;
  131.         }
  132.  
  133. /* T_CBREAK mode doesn't do erase or kill processing */
  134. /* also note that setting a special character to UNDEF disables it */
  135.  
  136.         if (rdmode & COOKED && !(mode & T_CBREAK) && ch != UNDEF) {
  137.             if ((char)ch == tty->sg.sg_erase) {  /* backspace */
  138.                 if (bytes_read > 0) {
  139.                     --ptr;
  140.                     erase(f, *ptr);
  141.                     bytes_read--;
  142.                 }
  143.                 continue;
  144.             }
  145.             else if ((mode & T_TOS) && ch == CTRL('X')) {
  146.                 while (bytes_read > 0) {
  147.                     --ptr;
  148.                     erase(f, *ptr);
  149.                     bytes_read--;
  150.                 }
  151.                 continue;
  152.             }
  153.             else if ((char)ch ==tty->ltc.t_rprntc || 
  154.                  (char)ch == tty->sg.sg_kill) {
  155.                 if (mode & T_TOS)
  156.                     put(f, '#');
  157.                 put(f, '\r');
  158.                 put(f, '\n');
  159.                 ptr = buf;
  160.                 if ((char)ch == tty->sg.sg_kill) {
  161.                     bytes_read = 0;
  162.                 }
  163.                 else {
  164.                     for (r = 0; r < bytes_read; r++, ptr++)
  165.                         put(f, *ptr);
  166.                 }
  167.                 continue;
  168.             }
  169.             else if ((char)ch == tty->ltc.t_werasc) {
  170.                 while (bytes_read > 0 &&
  171.                        !(ptr[-1] == ' ' || ptr[-1] == '\t')) {
  172.                     ptr--;
  173.                     erase(f, *ptr);
  174.                     bytes_read--;
  175.                 }
  176.                 continue;
  177.             }
  178.             else if ((char)ch == tty->ltc.t_lnextc) {
  179.                 put(f, '^');
  180.                 put(f, '\b');
  181.                 r = tty_getchar(f, RAW);
  182.                 if (r < 0)
  183.                     goto tty_error;
  184.                 else if (r == MiNTEOF)
  185.                     return bytes_read;
  186.                 ch = r & 0xff;
  187.                 goto stuff_it;
  188.             }
  189.             else if ((char)ch == tty->tc.t_eofc && !(mode & T_TOS))
  190.                 return bytes_read;
  191.         }
  192.  
  193. /* both T_CBREAK and T_COOKED modes have to do signals, though */
  194.         if ((rdmode & COOKED) && ch != UNDEF) {
  195.             if ((char)ch == tty->tc.t_intrc
  196.                  || (char)ch == tty->tc.t_quitc
  197.                  || (char)ch == tty->ltc.t_dsuspc
  198.                  || (char)ch == tty->ltc.t_suspc
  199.                 ) {
  200. /* the device driver raised the appropriate signal; if we get here, the
  201.    signal was caught by the user (or ignored). flush buffers and continue
  202.  */
  203.                 if (!(tty->sg.sg_flags & T_NOFLSH)) {
  204.                     DEBUG(("tty_read: flushing input"));
  205.                     bytes_read = 0;
  206.                     ptr = buf;
  207.                 }
  208.                 continue;
  209.             }
  210.             else if (ch == '\n' || (char)ch == tty->tc.t_brkc) {
  211.                 put(f, '\r');
  212.                 if (!(mode & T_TOS)) {
  213.                     *ptr = ch;
  214.                     put(f, '\n');
  215.                     bytes_read++;
  216.                 }
  217.                 return bytes_read;
  218.             }
  219.  
  220.         }
  221.  
  222. /* do the following for both RAW and COOKED mode */
  223. stuff_it:
  224.         *ptr++ = ch;
  225.         if (ch < ' ' && ch != '\t') {    /* ch is unsigned */
  226.             put(f, '^'); put(f, ch+'@');
  227.         }
  228.         else
  229.             put(f, ch);
  230.         bytes_read++;
  231.  
  232. /* for RAW mode, if there are no more characters then break */
  233.         if ( (mode & (T_RAW|T_CBREAK)) &&
  234.             !((rdmode & ESCSEQ) && (tty->state & TS_ESC))) {
  235.             r = 1;
  236.             (void)(*f->dev->ioctl)(f, FIONREAD, &r);
  237.             if (r <= 0) break;
  238.         }    
  239.     }
  240.  
  241.     return bytes_read;
  242. }
  243.  
  244. long
  245. tty_write(f, buf, nbytes)
  246.     FILEPTR *f;
  247.     const void *buf;
  248.     long nbytes;
  249. {
  250.     unsigned const char *ptr;
  251.     long c;
  252.     long bytes_written;
  253.     int mode, rwmode;
  254.     struct tty *tty;
  255.     int use_putchar = 0;
  256.     static long cr_char = '\r';
  257. #define LBUFSIZ 128
  258.     long lbuf[LBUFSIZ];
  259.  
  260.     tty = (struct tty *)f->devinfo;
  261.     assert(tty != 0);
  262.  
  263.     ptr = buf;
  264.     if (f->flags & O_HEAD) {
  265.         use_putchar = 1;
  266.         mode = T_RAW;
  267.     }
  268.     else if (curproc->domain == DOM_TOS)
  269. /* for TOS programs, 1 byte writes are always in raw mode */
  270.         mode = (nbytes == 1) ? T_RAW : T_TOS;
  271.     else
  272.         mode = tty->sg.sg_flags;
  273.  
  274.     rwmode = (mode & T_RAW) ? RAW : COOKED;
  275.  
  276.     bytes_written = 0;
  277.  
  278. /*
  279.  * "mode" can now be reduced to just T_CRMODE or not
  280.  */
  281.     if ((curproc->domain == DOM_MINT) && (mode & T_CRMOD) &&
  282.         !(mode & T_RAW))
  283.         mode = T_CRMOD;
  284.     else
  285.         mode = 0;
  286.  
  287. /*
  288.  * we always write at least 1 byte with tty_putchar, since that takes
  289.  * care of job control and terminal states. After that, we may be able
  290.  * to use (*f->dev->write) directly.
  291.  */
  292.  
  293.  
  294.     if (nbytes == 0) return bytes_written;
  295.     c = *ptr++;
  296.  
  297.     if (c == '\n' && mode) {    /* remember, "mode" now means CRMOD */
  298.         tty_putchar(f, cr_char, rwmode);
  299.     }
  300.     tty_putchar(f, c, rwmode);
  301.     nbytes--;
  302.     bytes_written++;
  303.  
  304.     if (use_putchar) {
  305.         while (nbytes-- > 0) {
  306.             c = *ptr++;
  307.             if (c == '\n' && mode)
  308.                 tty_putchar(f, cr_char, rwmode);
  309.             tty_putchar(f, c, rwmode);
  310.             bytes_written++;
  311.         }
  312.     } else {
  313. /* write in big chunks if possible; but never more than 1 line
  314.  * (so that ^S/^Q can happen reasonably quickly for the user)
  315.  */
  316.         long bytes_to_write = 0;
  317.         long *s = lbuf;
  318.  
  319.         while (nbytes-- > 0) {
  320.             c = *ptr++;
  321.             if (c == '\n') {
  322.                 if (bytes_to_write) {
  323.                     (*f->dev->write)(f, (char *)lbuf,
  324.                         bytes_to_write);
  325.                     bytes_to_write = 0;
  326.                     s = lbuf;
  327.                 }
  328.                 if (mode)    /* i.e. T_CRMODE */
  329.                     tty_putchar(f, cr_char, rwmode);
  330.                 tty_putchar(f, (long)c, rwmode);
  331.                 bytes_written++;
  332.             } else {
  333.                 *s++ = c;
  334.                 bytes_written++;
  335.                 bytes_to_write += 4;
  336.                 if (bytes_to_write >= LBUFSIZ*4) {
  337.                     (*f->dev->write)(f, (char *)lbuf,
  338.                              bytes_to_write);
  339.                     bytes_to_write = 0;
  340.                     s = lbuf;
  341.                 }
  342.             }
  343.         }
  344.         if (bytes_to_write) {
  345.             (*f->dev->write)(f, (char *)lbuf, bytes_to_write);
  346.         }
  347.     }
  348.  
  349.     return bytes_written;
  350. }
  351.  
  352. /* some notable scan codes */
  353. #define K_INSERT    0x52
  354. #define K_HOME        0x47
  355. #define K_UNDO        0x61
  356. #define K_HELP        0x62
  357. #define CURS_UP        0x48
  358. #define CURS_DN        0x50
  359. #define CURS_RT        0x4d
  360. #define CURS_LF        0x4b
  361. #define F_1        0x3b
  362. #define F_10        0x44
  363. #define F_11        0x54
  364. #define F_20        0x5d
  365. #define ALT_1        0x78
  366. #define ALT_0        0x81
  367.  
  368. /* Default function key table:
  369.  * entries:    0-9 are F1-F10
  370.  *            10-19 are F11-F20
  371.  *        20-23 are cursor up, down, right, and left
  372.  *        24-27 are help, undo, insert, and home
  373.  *        28-31 are shift+cursor up, down, right, and left
  374.  */
  375.  
  376. static char vt52xkey[256] = {
  377. '\033', 'P', 0, 0, 0, 0, 0, 0,
  378. '\033', 'Q', 0, 0, 0, 0, 0, 0,
  379. '\033', 'R', 0, 0, 0, 0, 0, 0,
  380. '\033', 'S', 0, 0, 0, 0, 0, 0,
  381. '\033', 'T', 0, 0, 0, 0, 0, 0,
  382. '\033', 'U', 0, 0, 0, 0, 0, 0,
  383. '\033', 'V', 0, 0, 0, 0, 0, 0,
  384. '\033', 'W', 0, 0, 0, 0, 0, 0,
  385. '\033', 'X', 0, 0, 0, 0, 0, 0,
  386. '\033', 'Y', 0, 0, 0, 0, 0, 0,
  387. '\033', 'p', 0, 0, 0, 0, 0, 0,
  388. '\033', 'q', 0, 0, 0, 0, 0, 0,
  389. '\033', 'r', 0, 0, 0, 0, 0, 0,
  390. '\033', 's', 0, 0, 0, 0, 0, 0,
  391. '\033', 't', 0, 0, 0, 0, 0, 0,
  392. '\033', 'u', 0, 0, 0, 0, 0, 0,
  393. '\033', 'v', 0, 0, 0, 0, 0, 0,
  394. '\033', 'w', 0, 0, 0, 0, 0, 0,
  395. '\033', 'x', 0, 0, 0, 0, 0, 0,
  396. '\033', 'y', 0, 0, 0, 0, 0, 0,
  397. '\033', 'A', 0, 0, 0, 0, 0, 0,
  398. '\033', 'B', 0, 0, 0, 0, 0, 0,
  399. '\033', 'C', 0, 0, 0, 0, 0, 0,
  400. '\033', 'D', 0, 0, 0, 0, 0, 0,
  401. '\033', 'H', 0, 0, 0, 0, 0, 0,
  402. '\033', 'K', 0, 0, 0, 0, 0, 0,
  403. '\033', 'I', 0, 0, 0, 0, 0, 0,
  404. '\033', 'E', 0, 0, 0, 0, 0, 0,
  405. '\033', 'a', 0, 0, 0, 0, 0, 0,
  406. '\033', 'b', 0, 0, 0, 0, 0, 0,
  407. '\033', 'c', 0, 0, 0, 0, 0, 0,
  408. '\033', 'd', 0, 0, 0, 0, 0, 0,
  409. };
  410.  
  411. static char unxbaud P_((long));
  412.  
  413. /* convert a number describing the baud rate into a Unix
  414.  * style baud rate number. Returns the Unix baud rate,
  415.  * or 16 (EXTA) if the rate is unknown
  416.  */
  417.  
  418. #define EXTA 16
  419.  
  420. static long ubaud[EXTA] = {
  421. 0L, 50L, 75L, 110L, 134L, 150L, 200L, 300L,
  422. 600L, 1200L, 1800L, 2400L, 4800L, 9600L, 19200L, 38400L
  423. };
  424.  
  425. static char
  426. unxbaud(baud)
  427.     long baud;
  428. {
  429.     int i;
  430.     for (i = 1; i < EXTA; i++) {
  431.         if (ubaud[i] == baud)
  432.             break;
  433.     }
  434.     return i;
  435. }
  436.  
  437. #define tosbaud(c) ( ((c) < 0 || (c) >= EXTA) ? -1L : ubaud[(unsigned)c] )
  438.  
  439. long
  440. tty_ioctl(f, mode, arg)
  441.     FILEPTR *f;
  442.     int mode;
  443.     void *arg;
  444. {
  445.     struct sgttyb *sg;
  446.     struct tchars *tc;
  447.     struct ltchars *ltc;
  448.     struct tty *tty;
  449.     struct winsize *sz;
  450.     struct xkey *xk;
  451.     char *xktab;
  452.     int i;
  453.     long baud;
  454.     short flags;
  455.  
  456.     if (!is_terminal(f)) {
  457.         DEBUG(("tty_ioctl(mode %x): file is not a tty", mode));
  458.         return EINVFN;
  459.     }
  460.     tty = (struct tty *)f->devinfo;
  461.     assert(tty != 0);
  462.  
  463.     switch(mode) {
  464.     case TIOCGETP:
  465.         sg = (struct sgttyb *)arg;
  466.     /* get input and output baud rates from the terminal device */
  467.         baud = -1L;
  468.         (*f->dev->ioctl)(f, TIOCIBAUD, &baud);
  469.         tty->sg.sg_ispeed = unxbaud(baud);
  470.         baud = -1L;
  471.         (*f->dev->ioctl)(f, TIOCOBAUD, &baud);
  472.         tty->sg.sg_ospeed = unxbaud(baud);
  473.     /* get terminal flags */
  474.         flags = 0;
  475.         if ((*f->dev->ioctl)(f, TIOCGFLAGS, &flags) == 0) {
  476.             tty->sg.sg_flags &= ~TF_FLAGS;
  477.             tty->sg.sg_flags |= (flags & TF_FLAGS);
  478.         }
  479.         *sg = tty->sg;
  480.         return 0;
  481.     case TIOCSETP:
  482.         sg = (struct sgttyb *)arg;
  483.         tty->sg = *sg;
  484.     /* set baud rates */
  485.         baud = tosbaud(sg->sg_ispeed);
  486.         (*f->dev->ioctl)(f, TIOCIBAUD, &baud);
  487.         baud = tosbaud(sg->sg_ospeed);
  488.         (*f->dev->ioctl)(f, TIOCOBAUD, &baud);
  489.     /* set parity, etc. */
  490.         flags = TF_8BIT;
  491.         if (sg->sg_flags & (T_EVENP|T_ODDP)) {
  492.             flags = TF_7BIT;
  493.         }
  494.         flags |= (sg->sg_flags & TF_FLAGS);
  495.         (*f->dev->ioctl)(f, TIOCSFLAGS, &flags);
  496.         return 0;
  497.     case TIOCGETC:
  498.         tc = (struct tchars *)arg;
  499.         *tc = tty->tc;
  500.         return 0;
  501.     case TIOCSETC:
  502.         tc = (struct tchars *)arg;
  503.         tty->tc = *tc;
  504.         return 0;
  505.     case TIOCGLTC:
  506.         ltc = (struct ltchars *)arg;
  507.         *ltc = tty->ltc;
  508.         return 0;
  509.     case TIOCSLTC:
  510.         ltc = (struct ltchars *)arg;
  511.         tty->ltc = *ltc;
  512.         return 0;
  513.     case TIOCGWINSZ:
  514.         sz = (struct winsize *)arg;
  515.         *sz = tty->wsiz;
  516.         return 0;
  517.     case TIOCSWINSZ:
  518.         sz = (struct winsize *)arg;
  519.         tty->wsiz = *sz;
  520.         return 0;
  521.     case TIOCGPGRP:
  522.         *((long *)arg) = tty->pgrp;
  523.         return 0;
  524.     case TIOCSPGRP:
  525.         tty->pgrp = (*((long *)arg) & 0x00007fffL);
  526.         return 0;
  527.     case TIOCSTART:
  528.         tty->state &= ~TS_HOLD;
  529.         return 0;
  530.     case TIOCSTOP:
  531.         tty->state |= TS_HOLD;
  532.         return 0;
  533.     case TIOCGXKEY:
  534.         xk = (struct xkey *)arg;
  535.         i = xk->xk_num;
  536.         if (i < 0 || i > 31) return ERANGE;
  537.         xktab = tty->xkey;
  538.         if (!xktab) xktab = vt52xkey;
  539.         xktab += i*8;
  540.         for (i = 0; i < 8; i++)
  541.             xk->xk_def[i] = *xktab++;
  542.         return 0;
  543.     case TIOCSXKEY:
  544.         xk = (struct xkey *)arg;
  545.         xktab = tty->xkey;
  546.         if (!xktab) {
  547.             xktab = kmalloc((long)256);
  548.             if (!xktab) return ENSMEM;
  549.             for (i = 0; i < 256; i++)
  550.                 xktab[i] = vt52xkey[i];
  551.             tty->xkey = xktab;
  552.         }
  553.         i = xk->xk_num;
  554.         if (i < 0 || i > 31) return ERANGE;
  555.         xktab += i*8;
  556.         for (i = 0; i < 7; i++)
  557.             xktab[i] = xk->xk_def[i];
  558.         xktab[7] = 0;
  559.         return 0;
  560.     default:
  561.         DEBUG(("tty_ioctl: bad function call"));
  562.         return EINVFN;
  563.     }
  564. }
  565.  
  566. /*
  567.  * function for translating extended characters (e.g. cursor keys, or
  568.  * ALT+key sequences) into either escape sequences or meta characters.
  569.  * for escape sequences, we return the the first character of the
  570.  * sequence (normally ESC) and set the tty's state so that subsequent
  571.  * calls to tty_getchar will pick up the remaining characters.
  572.  * Note that escape sequences are limited to 7 characters at most.
  573.  */
  574.  
  575. static int
  576. escseq(tty, scan)
  577.     struct tty *tty;
  578.     int scan;
  579. {
  580.     char *tab;
  581.     int i;
  582.  
  583.     switch(scan) {
  584.     case CURS_UP: i = 20; break;
  585.     case CURS_DN: i = 21; break;
  586.     case CURS_RT: i = 22; break;
  587.     case CURS_LF: i = 23; break;
  588.     case K_HELP:  i = 24; break;
  589.     case K_UNDO:  i = 25; break;
  590.     case K_INSERT:i = 26; break;
  591.     case K_HOME:  i = 27; break;
  592.     case CURS_UP+0x100: i = 28; break;
  593.     case CURS_DN+0x100: i = 29; break;
  594.     case CURS_RT+0x100: i = 30; break;
  595.     case CURS_LF+0x100: i = 31; break;
  596.     default:
  597.         if (scan >= F_1 && scan <= F_10) {
  598.             i = scan - F_1;
  599.         } else if (scan >= F_11 && scan <= F_20) {
  600.             i = 10 + scan - F_11;
  601.         } else
  602.             i = -1;
  603.     }
  604.  
  605.     if (i >= 0) {        /* an extended escape sequence */
  606.         tab = tty->xkey;
  607.         if (!tab) tab = vt52xkey;
  608.         i *= 8;
  609.         scan = tab[i++];
  610.         if (scan) {
  611.             if (tab[i] == 0) i = 0;
  612.             tty->state = (tty->state & ~TS_ESC) | i;
  613.         }
  614.         return scan;
  615.     }
  616.  
  617.     if (scan >= ALT_1 && scan <= ALT_0) {
  618.         scan -= (ALT_1-1);
  619.         if (scan == 10) scan = 0;
  620.         return (scan + '0') | 0x80;
  621.     }
  622.  
  623.     tab = *( ((char **)Keytbl((void *)-1UL, (void *)-1UL, (void *)-1UL)) + 2 );    /* gratuitous (void *) for Lattice */
  624.     scan = tab[scan];
  625.     if (scan >= 'A' && scan <= 'Z') return scan | 0x80;
  626.     return 0;
  627. }
  628.  
  629. long
  630. tty_getchar(f, mode)
  631.     FILEPTR *f;
  632.     int mode;
  633. {
  634.     struct tty *tty = (struct tty *)f->devinfo;
  635.     char c, *tab;
  636.     long r, ret;
  637.     int scan;
  638.     int master = f->flags & O_HEAD;
  639.  
  640.     assert(tty);
  641.  
  642. /* pty masters never worry about job control and always read in raw mode */
  643.     if (master) {
  644.         ret = (*f->dev->read)(f, (char *)&r, 4L);
  645.         return (ret != 4L) ? MiNTEOF : r;
  646.     }
  647.  
  648. /* job control check */
  649.     if (tty->pgrp != curproc->pgrp && tty->pgrp > 0) {
  650.         TRACE(("job control: tty pgrp is %d proc pgrp is %d",
  651.             tty->pgrp, curproc->pgrp));
  652.         killgroup(curproc->pgrp, SIGTTIN);
  653.     }
  654.  
  655.     if (mode & COOKED)
  656.         tty->state |= TS_COOKED;
  657.     else
  658.         tty->state &= ~TS_COOKED;
  659.  
  660.     c = UNDEF+1;    /* set to UNDEF when we successfully read a character */
  661.  
  662. /* we may be in the middle of an escape sequence */
  663.     scan = (tty->state & TS_ESC);
  664.     if (scan != 0) {
  665.         if (mode & ESCSEQ) {
  666.             tab = tty->xkey ? tty->xkey : vt52xkey;
  667.             r = (unsigned char) tab[scan++];
  668.             if (r) {
  669.                 c = UNDEF;
  670.                 if (tab[scan] == 0) scan = 0;
  671.             }
  672.             else
  673.                 scan = 0;
  674.             tty->state = (tty->state & ~TS_ESC) | scan;
  675.         }
  676.         else
  677.             tty->state &= ~TS_ESC;
  678.     }
  679.  
  680.     while (c != UNDEF) {
  681.         ret = (*f->dev->read)(f, (char *)&r, 4L);
  682.         if (ret != 4L) {
  683.             DEBUG(("EOF on tty device"));
  684.             return MiNTEOF;
  685.         }
  686.         c = r & 0x00ff;
  687.         scan = (int)((r & 0x00ff0000L) >> 16);
  688.         if ( (c == 0) && (mode & ESCSEQ) && scan) {
  689.             c = UNDEF;
  690.     /* translate cursor keys, etc. into escape sequences or
  691.      * META characters
  692.      */
  693.             r = escseq(tty, scan);
  694.         } else if ((mode & ESCSEQ) && ((scan == CURS_UP && c == '8') ||
  695.                (scan == CURS_DN && c == '2') ||
  696.                (scan == CURS_RT && c == '6') ||
  697.                (scan == CURS_LF && c == '4'))) {
  698.             c = UNDEF;
  699.             r = escseq(tty, scan+0x100);
  700.         } else if (mode & COOKED) {
  701.             if (c == UNDEF)
  702.                 ;    /* do nothing */
  703.             else if (c == tty->ltc.t_dsuspc)
  704.                 killgroup(curproc->pgrp, SIGTSTP);
  705.             else if (c == tty->tc.t_intrc)
  706.                 killgroup(curproc->pgrp, SIGINT);
  707.             else if (c == tty->tc.t_stopc)
  708.                 tty->state |= TS_HOLD;
  709.             else if (c == tty->tc.t_stopc)
  710.                 tty->state &= ~TS_HOLD;
  711.             else
  712.                 c = UNDEF;
  713.         }
  714.         else
  715.                 c = UNDEF;
  716.     }
  717.  
  718.     if (mode & ECHO)
  719.         tty_putchar(f, r, mode);
  720.  
  721.     return r;
  722. }
  723.  
  724. /*
  725.  * tty_putchar: returns number of bytes successfully written
  726.  */
  727.  
  728. long
  729. tty_putchar(f, data, mode)
  730.     FILEPTR *f;
  731.     long data;
  732.     int mode;
  733. {
  734.     struct tty *tty;
  735.     int master;        /* file is pty master side */
  736.     char ch;
  737.  
  738.     tty = (struct tty *)f->devinfo;
  739.  
  740.     master = f->flags & O_HEAD;
  741.  
  742. /* pty masters don't need to worry about job control */
  743.     if (master) {
  744.         ch = data & 0xff;
  745.  
  746.         if ( (tty->state & TS_COOKED) && ch != UNDEF) {
  747. /* see if we're putting control characters into the buffer */
  748.             if (ch == tty->tc.t_intrc) {
  749.                 tty->state &= ~TS_HOLD;
  750.                 killgroup(tty->pgrp, SIGINT);
  751.                 return 4L;
  752.             }
  753.             else if (ch == tty->tc.t_quitc) {
  754.                 tty->state &= ~TS_HOLD;
  755.                 killgroup(tty->pgrp, SIGQUIT);
  756.                 return 4L;
  757.             }
  758.             else if (ch == tty->ltc.t_suspc) {
  759.                 tty->state &= ~TS_HOLD;
  760.                 killgroup(tty->pgrp, SIGTSTP);
  761.                 return 4L;
  762.             }
  763.             else if (ch == tty->tc.t_stopc) {
  764.                 tty->state |= TS_HOLD;
  765.                 return 4L;
  766.             }
  767.             else if (ch == tty->tc.t_startc) {
  768.                 tty->state &= ~TS_HOLD;
  769.                 return 4L;
  770.             }
  771.             else if (tty->state & TS_HOLD) {
  772.                 return 0;
  773.             }
  774.         }
  775.         goto do_putchar;
  776.     }
  777. /* job control checks */
  778. /* AKP: added T_TOSTOP; don't stop BG output if T_TOSTOP is clear */
  779.     if (tty->pgrp != curproc->pgrp && tty->pgrp > 0 
  780.         && (tty->sg.sg_flags & T_TOSTOP)) {
  781.         TRACE(("job control: tty pgrp is %d proc pgrp is %d",
  782.             tty->pgrp, curproc->pgrp));
  783.         killgroup(curproc->pgrp, SIGTTOU);
  784.     }
  785.  
  786.     if (mode & COOKED) {
  787.         tty->state |= TS_COOKED;
  788.         while (tty->state & TS_HOLD)
  789.             nap(60);    /* sleep for 60 milliseconds */
  790.     }
  791.     else
  792.         tty->state &= ~TS_COOKED;
  793.  
  794. do_putchar:
  795.     return (*f->dev->write)(f, (char *)&data, 4L);
  796. }
  797.